import * as util from './util.js';

async function main() {
    // WebGPU 是异步 API，所以需要使用 async/await 来处理
    const adapter = await navigator.gpu?.requestAdapter();
    const device = await adapter?.requestDevice();
    if (!device) {
        util.fail ('need a browser that supports WebGPU');
        return;
    }

    const canvas = document.querySelector('canvas');    
    const context = canvas.getContext('webgpu');
    // 询问系统首选的画布格式是什么( rgba8unorm 或 bgra8unorm)。
    // 这其实并不重要，重要的是通过查询，可以让用户的系统以最快的速度运行。
    const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
    // 调用 configure 将format传入 webgpu 画布上下文。
    // 将device传入画布，从而将画布与创建的设备关联起来。
    context.configure({
        device,
        format: presentationFormat,
    });

    const wgslCode = await util.loadWGSLSoureFile('./shaders/interstage.wgsl'); 

    const module = device.createShaderModule({
        label: 'our hardcoded triangle shaders',
        code: wgslCode,
    });

    const pipeline = device.createRenderPipeline({
        label: 'our hardcoded triangle pipeline',
        layout: 'auto',
        vertex: {
            module,
        },
        fragment: {
            module,
            targets: [{ format: presentationFormat }],
        },
    });

    const renderPassDescriptor = {
        label: 'our basic canvas renderPass',
        colorAttachments: [
            {
                clearValue: [0.3, 0.3, 0.3, 1],
                // load意思是将纹理的现有内容加载到 GPU 中
                loadOp: 'clear', // 指定在绘制前将纹理清除为clearValue
                // storeOp: 'store'表示存储绘制结果。也可儿童discard来丢弃绘制的结果
                storeOp: 'store', // 
            },
        ],
    };

    // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
    // WeakMap 对象是一组键/值对的集合，其中的键是弱引用的。其键必须是对象，而值可以是任意的。
    // WeakMap 对象中的键值对在垃圾回收机制运行时会被移除。
    const canvasToSizeMap = new WeakMap();

    function resizeCanvasToDisplaySize(canvas) {
        // Get the canvas's current display size
        let { width, height } = canvasToSizeMap.get(canvas) || canvas;

        // Make sure it's valid for WebGPU
        width = Math.max(1, Math.min(width, device.limits.maxTextureDimension2D));
        height = Math.max(1, Math.min(height, device.limits.maxTextureDimension2D));

        // Only if the size is different, set the canvas size
        const needResize = canvas.width !== width || canvas.height !== height;
        if (needResize) {
            canvas.width = width;
            canvas.height = height;
        }
        return needResize;
    }
    
    function render() {
        resizeCanvasToDisplaySize(canvas);

        renderPassDescriptor.colorAttachments[0].view =
            context.getCurrentTexture().createView();

        const encoder = device.createCommandEncoder({ label: 'our encoder' });
        const pass = encoder.beginRenderPass(renderPassDescriptor);
        pass.setPipeline(pipeline);
        pass.draw(3);
        pass.end();

        const commandBuffer = encoder.finish();
        device.queue.submit([commandBuffer]);
    }

    // ResizeObserver 接口监视 Element 内容盒或边框盒或者 SVGElement 边界尺寸的变化。
    // ResizeObserver 避免了通过回调函数调整大小时，通常创建的无限回调循环和循环依赖项。
    const observer = new ResizeObserver(entries => {
        for (const entry of entries) {
            canvasToSizeMap.set(entry.target, {
                width: entry.contentBoxSize[0].inlineSize,
                height: entry.contentBoxSize[0].blockSize,
            });
        }
        render();
    });

    observer.observe(canvas);
}



main();
